package com.simpou.tests.persistence;

import com.simpou.commons.persistence.dao.BasicDAO;
import com.simpou.commons.persistence.jpa.dao.impl.DefaultJpaDAOImpl;
import com.simpou.tests.persistence.entity.TestDaosEntity2;
import com.simpou.tests.persistence.entity.TestDaosEntity;
import com.simpou.commons.utils.lang.annot.RandomFillableConfig;
import com.simpou.commons.utils.tests.TestRunner;
import com.simpou.commons.utils.tests.annot.ClassTest;
import com.simpou.commons.utils.tests.annot.Repeat;
import com.simpou.tests.persistence.exception.DaoException;

import static org.junit.Assert.*;

import org.junit.runner.RunWith;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.persistence.RollbackException;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;


@ClassTest(EntitiesTester.class)
@RunWith(TestRunner.class)
public class EntitiesTesterITCase {
    private static BasicDAO dao1;
    private static BasicDAO dao2;
    private static int curBoolControl = 0;
    private static final boolean[][] boolControls = {
            { true, false },
            { true, true },
            { false, true },
            { false, false }
        };

    @BeforeClass
    public static void setUpClass() throws Exception {
        final EntityManager em = Persistence.createEntityManagerFactory(Constants.PU_NAME)
                                            .createEntityManager();
        dao1 = new DefaultJpaDAOImpl(em);
        dao2 = new DefaultJpaDAOImpl(em);
    }

    @Before
    public void setUp() {
//        TestDaosEntity2.allowInstantiate = boolControls[curBoolControl][0];
        curBoolControl = (curBoolControl + 1) % boolControls.length;
    }

    @After
    public void tearDown() {
    }

    @Test
    public void testFillRandom() throws Exception {
        dao1.getTransaction().begin();

        List<Exception> exceptions = TesterHelper.fillRandom(TestDaosEntity.class,
                dao1);
        dao1.getTransaction().commit();
        assertTrue(exceptions.isEmpty());

        List<TestDaosEntity> list = null;//dao1.getList();
        assertFalse(list.isEmpty());

        RandomFillableConfig config = TestDaosEntity.class.getAnnotation(RandomFillableConfig.class);
        assertTrue(list.size() >= config.minLength());
        assertTrue(list.size() <= config.maxLength());
    }

    @Test
    @Repeat(4)
    public void testFillRandom_2() throws Exception {
        dao2.getTransaction().begin();

        List<Exception> exceptions = null;

        try {
            exceptions = TesterHelper.fillRandom(TestDaosEntity2.class, dao2);
            assertTrue(exceptions.isEmpty());
        } catch (IllegalStateException e) {
            // falha na instanciação
            assertNull(exceptions);
        }

        try {
            dao2.getTransaction().commit();
        } catch (RollbackException rollbackException) {
        }
    }

    @Test
    public void testDoRandomCrud() throws Exception {
        dao1.getTransaction().begin();
        //dao1.deleteAll();

        List<DaoException> exceptions = null;//EntitiesTester.doRandomCrud(TestDaosEntity.class, dao1);
        dao1.getTransaction().commit();
        assertTrue(exceptions.isEmpty());

        List<TestDaosEntity> list = null;//dao1.getList();
        assertTrue(list.isEmpty());
    }

    @Test
    @Repeat(8)
    public void testDoRandomCrud_2() throws Exception {
        List<DaoException> exceptions = null;
        dao2.getTransaction().begin();
    //    dao2.deleteAll();

        try {
            exceptions = null;//EntitiesTester.doRandomCrud(TestDaosEntity2.class, dao2);

            // se não gerar exceção, lista deve ser vazia
            assertTrue(exceptions.isEmpty());
        } catch (IllegalStateException e) {
            // falha na instanciação
            assertNull(exceptions);
        }

        try {
            dao2.getTransaction().commit();
        } catch (RollbackException rollbackException) {
        }
    }

    @Test
    public void testNewRandomEntity() throws Exception {
        TestDaosEntity entity = EntitiesTester.newRandomEntity(TestDaosEntity.class);
        assertNotNull(entity);
    }
}
